C++ 类的继承基础

类是 C++ 的一大特色,但是只知道类却不会类的继承是没有太大意义的。今天,我们就来聊一下类的继承。

类,即 class,与结构体 struct 类似,同时也添加了一些新的功能。

类中的元素分 public、protected 和 private 三种,在继承时有所体现:

继承类型 基类 public 元素在 派生类的类别 基类 protected 元素在 派生类的类别 基类 private 元素在 派生类的类别
public 继承 public protected 不继承
protected 继承 protected protected 不继承
private 继承 private private 不继承

注意继承的种类改变不了以下几点:

  • private 成员只能在类内及友元中被访问,无法被派生类访问;
  • protected 成员可以在派生类访问。

下面看一个具体的例子:

//By: Luogu@rui_er(122461)
#include <bits/stdc++.h>
using namespace std;

class A { // 定义基类 A 
public:
	int a;
	A() {
		a = 1;
		b = 2;
		c = 3;
		d = 4;
	}
	void print() {
		cout<<a<<endl; // 正确,类中成员 
		cout<<b<<endl; // 正确,类中成员 
		cout<<c<<endl; // 正确,类中成员 
		cout<<d<<endl; // 正确,类中成员 
	}
public:
	int b;
protected:
	int c;
private:
	int d;
}; 
class B : public A { // 从 A 通过 public 继承得到派生类 B 
public:
	int a;
	B(int x) {
		A();
		a = x;
	}
	void print() {
		cout<<a<<endl; // 正确,类中成员 
		cout<<b<<endl; // 正确,在基类中是 public 成员,在派生类依然是 public 成员 
		cout<<c<<endl; // 正确,在基类中是 protected 成员,在派生类依然是 protected 成员 
		cout<<d<<endl; // 错误,基类的 private 成员不能被继承 
	}
};

int main() {
	B b(5);
	cout<<b.a<<endl; // 正确,类中 public 成员 
	cout<<b.b<<endl; // 正确,继承为 public 成员 
	cout<<b.c<<endl; // 错误,继承为 protected 成员,不能在类外访问 
	cout<<b.d<<endl; // 错误 
	return 0;
}

这里是 public 继承,另外两种继承可以以此类推。


虚拟继承

在类 A 中的函数 f() 继承到 B 中需要重写,怎么办?

! 如果只是想根据基类函数加一些代码:

class A {
public:
    void f() {
        puts("A");
    }
};
class B : public A {
public:
    void f() {
        A::f(); // 调用基类的 f() 函数
        puts("B"); // 需要额外添加的代码
    }
};

这里基类指针可以指向派生类的对象:

class A {
public:
    int a;
};
class B : public A {
public:
    int b;
};
int main() {
    B b;
    b.a = 1;
    b.b = 2;
    A* p = &b;
    printf("%d\n", p->a);
    return 0;
}

! 问题

class A {
public:
    void f() {
        puts("A");
    }
};
class B : public A {
public:
    void f() {
        puts("B");
    }
};
int main() {
    B b;
    A* p = &b;
    p->f(); // 这一行
}

程序中的 p->f() 到底指哪一个?

! 继承时重写函数

如果一个函数需要被重写,在基类中应声明为 virtual,此时将调用子类的函数。

class A {
public:
    virtual void f() {
        puts("A");
    }
};
class B : public A {
public:
    void f() {
        puts("B");
    }
};
int main() {
    B b;
    A* p = &b;
    p->f(); // 这一行
}

继承中的构造、析构函数问题

class A {
public:
    A() : a(0), b(0) {
        puts("A()");
    }
    A(int x, int y) : a(x), b(y) {
        puts("A(x, y)");
    }
    ~A() {
        puts("~A()");
    }
private:
    int a, b;
};
class B : public A {
public:
    B() : A(0, 1) {
        puts("B()");
    }
    ~B() {
        puts("~B()");
    }
};
int main() {
    A* p = new B();
    delete p;
}

在这个程序中,delete p 可能导致程序出错甚至崩溃,这里需要将 ~A() 声明为 virtual:

virtual ~A()

多重继承

class father {/*Do somthing..*/};
class mother {/*Do something..*/};
class son : public father, public mother {/*Do somthing..*/};

注意这里如果 father 和 mother 中出现同名变量可能导致错误。